.TH SYSLOG 3 2007-09-10 "NSN SOA" "NSN SOA Programmer's Manual"
.SH NAME
trace_init, trace_exit, trace_open, trace_close, trace_set_destination, trace_set_header, trace_add_component, trace_del_component, trace_write, trace_enable, trace_disable, trace_on, trace_off, trace_parse_flags, trace_list_flags, trace_reset_filters, trace_add_simple_filter, trace_del_simple_filter - produce filterable trace messages
.br
.SH INTRODUCTION

The trace library provides a way for applications to produce trace messages.
Trace messages are primarily intended for developers to diagnose problems and
find bugs in the implementation of the application. They are not primarily
meant to be used by or exposed to users of the applications.

Trace messages are used to expose as much information about the internal
workings of an application as possible. This typically includes control flow
or execution path traces (which functions are called with what arguments,
what are the return values), dumps of inputs and outputs, application state
change traces (event dumps, dumps of the old and new states), dumps of internal
objects, etc. This information along with the source code (and a thorough
understanding of the ideas, principles, and algorithms behind the application)
is then used to find bugs in the implementation.

In any non-trivial traceable application, the total amount of possible trace
messages is enormous. Control over exactly what messages are produced is as
essential as being able to produce the messages in the first place. The lack
of control pushes the application developer from one bad extreme to the other,
from no information whatsoever to an ultimate information overflow. Also
producing the full spectrum of trace messages changes the dynamic real-time
behaviour of the application. The timing of events changes and performance
degrades as the amount of messages grow. Reproducing known (ie. observed)
erroneous behaviour becomes increasingly dangerous in production environments
(drown in trace messages till system crash), and difficult in a controlled
lab environment (changes in real-time behaviour prevents some bugs from being
triggered). Hence a way for fine-grained trace message suppression is necessary.
The library provides three levels of message suppression: global context-
based suppression, class-based suppression, and tag-based filtering. These
are all runtime-configurable.

Typically non-trivial applications are constructed from a set of generic
reusable components (separated to generalized libraries), a set of domain-
or application-specific but reusable components (separated to domain-specific
libraries), some application specific logic, and gluing code to tie it all
together. Similarly the trace library is meant to be a reusable and generic
component that should fit in to a large set of applications, software
components and libraries, ideally without modifications. Neither co-operation
nor co-ordination should be necessary for developers to avoid conflicts
between independently developed components when they are linked statically
or dynamically to a single application, even if all of the components use the
trace library. To avoid the need of a priori knowledge about all the software
components and their tracing needs and capabilities, the library provides a
way for components to dynamically register for tracing.

.SH SYNOPSIS
.B #include <trace/trace.h>
.sp
.BI "int trace_init(void);"
.br
.BI "void trace_exit(void);"
.br
.BI "int trace_open(trace_context_t *context, char *name);"
.br
.BI "void trace_close(trace_context_t *context);"
.br
.BI "int trace_add_component(trace_context_t *context, trace_component_t *component);"
.br
.BI "void trace_del_component(trace_context_t *context, trace_component_t *component);"
.br
.BI "int trace_set_destination(trace_context_t *context, const char *destination);"
.br
.BI "int trace_set_header(trace_context_t *context, const char *format);"
.br
.BI "int trace_enable(trace_context_t *context);"
.br
.BI "int trace_disable(trace_context_t *context);"
.br
.BI "int trace_off(trace_context_t *context, int flag);"
.br
.BI "int trace_on(trace_context_t *context, int flag);"
.br
.BI "#define trace_write(context, flag, tags, format, args...)"
.br
.BI "#define TRACE_DECLARE_TAGS(tags, maxtags, totalvalues)"
.br
.BI "#define trace_tag_addf(tags, key, format, args...)"
.br
.BI "#define trace_tag_add(tags, key, value)"
.br
.BI "int trace_parse_flags(const char *request);"
.SH DESCRIPTION
.BR trace_init ()
is used to initialise the trace library. It must be invoked once prior to
calling any other functions of the trace library.
.BR trace_exit ()
can be used to deinitialize the library. It frees any potential resources
consumed by the library. Once the trace library is deinitialized, no other
functions should be called until it is reinitialized with
.BR trace_init ()
again.

Typically, applications invoke
.BR trace_init ()
during their startup/initialization phase. Similarly they invoke
.BR trace_exit ()
to clean up during their shutdown/deinitialization phase, usually right
before
.BR exit(2)
ing.

.BR trace_open ()
initializes the given trace
.I context.
A trace context must be initialized before it can be passed to any other
functions of the trace library.
.I name
is a symbolic name given to the context. This name can be later used to refer
to the context eg. when configuring message suppression outside of the
application.
.BR trace_close ()
closes deinitializes the given
.I context.
Once deinitialized it cannot be used until it is reinitialized using
.BR trace_open ()
again.

.BR trace_add_component ()
registers a component for tracing. From the libraries point of view a
component is merely a collection of trace flags that are later used to classify
trace messages. During registration the library dynamically allocates values
for the requested flags. These flags are unique within the given
.I context.
.BR trace_del_component ()
unregisters the given
.I component
from the trace
.I context.

.BR trace_set_destination ()
controls where trace messages for the given trace
.I context
are emitted. 
.I destination
is one of
.BR TRACE_TO_STDOUT,
.BR TRACE_TO_STDERR,
.BR TRACE_TO_FILE(path).
.BR TRACE_TO_FILE(path)
appends subsequent messages to the file specified by
.I path.

.BR trace_set_header ()
changes the format of the header that is output before every trace
message for
.I context.
.I format
points to a
.BR printf-\c
like formatting string that controls how the header will exactly look like.
It can contain special directives that are substituted by some corresponding
information. Any other (ie. non-directive) part of the
.I format
string is copied verbatim to the generated log entry. A directive consists
of percent sign (%) followed by a single directive character. Any unrecognized
directive character is copied verbatim. The recognized directives are:
.TP
.B i
replaced by the name of the
.I context.
This is the
.I name
parameter supplied to
.BR trace_open ().
.TP
.B D
replaced by absolut UTC time with millisecond resolution.
.TP
.B d
replaced by delta time, ie. the time since the prviously produced message
in the same
.I context.
.TP
.B T
replaced by the tags attached to the trace message.
.TP
.B c
replaced by the component name of the flag of the trace message.
.TP
.B f
replaced by the trace flag name.
.TP
.B W
replaced by the location from which trace_write was called in the format
function@file:linenumber. 
.TP
.B C
replaced by the function name (gcc macro
.BR __FUNCTION__\c
) of the caller.
.TP
.B F
replaced by the filename (ANSI C macro
.BR __FILE__\c
)
of the caller.
.TP
.B L
replaced by the line number (ANSI C macro
.BR __LINE__\c
)
of the caller.
.PP
.BR trace_disable ()
globally suppresses all trace messages in
.I context
without changing any of the tracing flags or filters.
Conversely
.BR trace_enable ()
removes global suppression from
.I context.
This is typically used to set up a complex combination of trace flags and
tag filters, temporarily suppress all messages using
.BR trace_disable ()
until a precondition is met (typically until a bug is hit), then quickly
re-enable messages using
.BR trace_enable ().

.BR trace_on ()
is used to turn on the given trace
.I flag
within
.I context.
When a flag is on, all messages corresponding to that flag are emitted unless
they are suppressed because of global suppression (ie.
.BR trace_disable ())
or they are filtered by the tag filters of
.I context.
.BR trace_off
does the opposite. It turns off the given trace
.I flag
within
.I context.
No messages corresponding to
.I flag
are emitted until
.I flag
is turned on again.

.BR trace_write ()
is used to produce a trace message within the given trace
.I context
according to the
.BR printf(3)-\c
style
.I format
string and any arguments required by it.
.I tags
specify the set of tags that are attached to the message.

There is a set of convenience macros and functions provided for manipulating
sets of tags. To declare a tag set
.I tags
containing up to
.I maxtags
tags
and reserve
.I totalvalues
bytes of storage for tag values, use
.BI "TRACE_DECLARE_TAGS(tags, maxtags, totalvalues)."
You can add a tag with
.I key
and a 
.BR printf(3)-\c
style formatted value
to this tagset
using
.BI "trace_tag_addf(tags, key, format, ...)."
To add a tag with a preformatted
.I key
and
.I value
use
.BI "trace_tag_add(tags, key, value)."
These macros allocate everything on the stack of the caller. The scope of
the tagset is strictly limited to the innermost block where they were
declared. Once control reaches the end of that block everything is freed
automatically. This is a deliberate design choice to minimize overhead and
the possibility of memory leaks. As tags are only needed for filtering during
the call to
.BR trace_write
this should not be a problem. Keep in mind that you cannot pass pointers to
tagsets allocated this way up in the function call stack.
.SH "MESSAGE FILTERING"

A trace message is subject to three levels of filtering. If global
suppression is on for
.I context,
the message is immediately suppressed. Similarly, if
.I flag
is off within
.I context
the message is suppressed. Otherwise the filters of
.I context
are applied to the attached trace
.I tags
to see if the message should be emitted.
If any of the filters match the message is immediately emitted. Otherwise
the message is suppressed.

A filter consists of a set of expressions. An expression is a key/value pair.
There a two types of filters supported, simple filters and regexp filters.
In simple filters expression values are plain strings. In regexp filters
expression values can be regular expressions. A trace message is passed
through (ie. emitted) if it matches any of the filters. A message matches
a filter if its associated set of tags matches any filters. A set of tags
matches a filter if every expression in the filter is satisfied by at
least one tag. A tag satisfies a simple filter expression if their keys
and values are identical. A tag satisfies a regexp filter expression if
their keys are identical and the tags value is matched by the expressions
regexp value.

NOTE: Regexp filters are currently not implemented.

.BR trace_reset_filters ()
deletes all filters from the given trace
.I context.
.BR trace_add_simple_filter ()
adds the filter specified by
.I tags
to the given trace
.I context.
.BR trace_del_simple_filter ()
does the inverse. It removes the filter
specified by
.I tags
from the given trace
.I context.

.SH "RUNTIME CONFIGURATION"

The library provides a set of functions for interpreting external runtime
configuration requests. This set does not implement a complete runtime
configuration interface. As a general design principle the library tries to
provide mechanisms whenever possible instead of forcing policies on
applications. The most appropriate policy can then be implemented for each
and every application using the provided mechanisms. Adhering to this principle,
the library is not concerned with how the application gets the external
configuration requests. Some applications might use a set of configuration
files and signal(2)s, others might have a management console where one can
connect(2) and send(2) management commands. Some applications might have both.
All in all, it is left to the developer to decide what is the most suitable
for each application. The library simply provides functions that parse and
execute configuration requests once they are obtained in some
application-specific manner.

.BR trace_parse_flags ()
parses a configuration
.I request
string to change the set of active trace flags and applies the requested
changes. The format of the configuration string is (in EBNF)

.RS

request ::= optional_command context_flags
.br
optional_command ::= "trace" "flag" | "flag" | epsilon
.br
context_flags ::= context_flag | context_flags ";" context_flag
.br
context_flag ::= context "." component "=" flags
.br
flags ::= flag | flags "," flag
.br
flag ::= optional_plus_minus trace_flag
.br
optional_plus_minus ::= \*(lq + \*(rq | "-" | epsilon
.br
.RE

Eg. a configuration string might look like this:

.RS
trace flags gw.sip=+sessions,+requests;gw.mixer=+sessions,-media

.RE
This would request to turn on the flags
.I sessions
and
.I requests
for the
component
.I sip
in the context of
.I gw,
then turn on the flag
.I sessions
and off the flag
.I media
for the component
.I mixer
in the context of
.I gw.

There are special wildcards for matching all context, component and flag names.
The wildcard for context and component names is "*", for flag names it is
"all". Changes are deltas wrt. the current configuration and are applied
sequentially in the order they are specified. States of flags not listed or
matched by wildcards are not changed. An example using wildcards could be

.RS
trace flags *.memory=-all;*.sip=+requests;*.*=-media

.RE

NOTE 1: A future release might change the trace flag notation so that omitting
a sign will be taken as an absolute rather than a delta change (ie. "foo" will
not be considered a synonym of "+foo" but rather a synonym of "-all,+foo").
To protect yourself against this change never omit the sign.

NOTE 2: The trace library might implicitly register flags that are allocated
for/from each context and component. These are used internally by the library
itself for debugging and to generate warnings about improper use of the
interfaces. These flags are never matched by any of the wildcards. Rather to
control these flags they must be explicitly referenced.


.SH "BUGS"

.SS Missing / Partially Implemented Features
.IP \(bu 2
Regexp filters are not implemented yet.
.IP \(bu 2
Simple filters are always executed using the slowest fallback path.
.IP \(bu 2
Runtime configuration parser for filters (akin to trace_parse_flags) is
still missing. IOW filters cannot be pushed into the library from outside of
the applications (unless the application itself implements parsing strings
into filters).

Please, report any other bugs.

.SH "SEE ALSO"
.BR printf(3)
